/* verilator lint_off UNUSEDSIGNAL */
`include "defines.svh"
`default_nettype wire

module MEM_STAGE(
    input clk,
    input reset,
    input logic exe_valid,
    output logic mem_ready,
    output logic mem_valid,
    input logic wb_ready, 
    input exe_to_mem_bus_t exe_to_mem_bus,
    output mem_to_wb_bus_t mem_to_wb_bus,

    // bypass
    output mem_to_id_bypass_t mem_to_id_bypass,
    input wb_to_front_bypass_t wb_to_front_bypass,
    
    // sram
    input word_t data_sram_rdata,
    input logic axi_data_flushreq
);
exe_to_mem_bus_t exe_to_mem_bus_r;

// assign stallreq_csr_from_mem = exe_to_mem_bus_r.sel_exception == `EXC_ON;

word_t data_sram_rdata_r;


logic em_shake,mw_shake,stall_mem,flush_mem;
assign em_shake = exe_valid & mem_ready;
assign mw_shake = wb_ready & mem_valid;
assign stall_mem = `OFF;
assign flush_mem = wb_to_front_bypass.ecall_en | axi_data_flushreq;
always_ff @(posedge clk) begin
    if(reset) begin
        mem_valid <= `OFF;
    end else begin
        mem_valid <= em_shake;
    end
end

assign mem_ready = wb_ready;


// 接收
always_ff @(posedge clk) begin
    if(reset) begin
        exe_to_mem_bus_r <= `NULL;
        data_sram_rdata_r <= `NULL;
    end else if (em_shake & ~stall_mem & ~flush_mem) begin
        exe_to_mem_bus_r <= exe_to_mem_bus;
        data_sram_rdata_r <= data_sram_rdata;
    end else if(flush_mem & ~stall_mem) begin
        exe_to_mem_bus_r <= `NULL;
        data_sram_rdata_r <= `NULL;
    end
end


// 发送
always_comb begin
    if(reset) begin
        mem_to_wb_bus = `NULL;
    end else begin
        mem_to_wb_bus = '{
            mem_pc,
            exe_to_mem_bus_r.debug_dnpc,
            exe_to_mem_bus_r.load_en & mem_valid,
            exe_to_mem_bus_r.store_en & mem_valid,
            exe_to_mem_bus_r.alu_result,
            mem_inst,
            
            exe_to_mem_bus_r.rf_wen & mem_valid,
            exe_to_mem_bus_r.rf_waddr,
            writeback_data,
        
            exe_to_mem_bus_r.sel_exception,
            exe_to_mem_bus_r.rfc_waddr,
            csr_writeback_data
        };
    end
end

word_t mem_pc,mem_inst,MASKED_data_sram_rdata;
logic[3:0] ls_mask;
always_comb begin
    if(reset == `ON) begin 
        {mem_pc,mem_inst} = `NULL;
        // ls_mask = `NULL;
        MASKED_data_sram_rdata = `NULL;
    end else begin
        {mem_pc,mem_inst} = {exe_to_mem_bus_r.pc,exe_to_mem_bus_r.inst};
    
        case(exe_to_mem_bus_r.sel_mask)
            `M_W: begin 
                // ls_mask    = 4'b1111;
                MASKED_data_sram_rdata = data_sram_rdata_r;
            end
            `M_B: begin
                // ls_mask    = 4'b0001;
                MASKED_data_sram_rdata = {{24{data_sram_rdata_r[7]}},data_sram_rdata_r[7:0]};
            end
            `M_H: begin
                // ls_mask    = 4'b0011;
                MASKED_data_sram_rdata = {{16{data_sram_rdata_r[15]}},data_sram_rdata_r[15:0]};
            end
            `M_LBU: begin
                // ls_mask  = 4'b0001;
                MASKED_data_sram_rdata = {24'b0,data_sram_rdata_r[7:0]};
            end
            `M_LHU: begin
                // ls_mask  = 4'b0011;
                MASKED_data_sram_rdata = {16'b0,data_sram_rdata_r[15:0]};
            end
            default: begin
                // ls_mask = 4'b0000;
                MASKED_data_sram_rdata = 32'b0;
            end
        endcase
    end
end

// assign data_sram_pc = mem_pc;
// assign data_sram_en = (exe_to_mem_bus_r.store_en | exe_to_mem_bus_r.load_en) & mem_valid;
// assign {data_sram_addr,
//         data_sram_wen,
//         data_sram_mask,
//         data_sram_wdata} = {data_sram_en & mem_valid ? exe_to_mem_bus_r.alu_result : 32'b0,
//                             exe_to_mem_bus_r.store_en & mem_valid,
//                             ls_mask,
//                             exe_to_mem_bus_r.store_data};

word_t load_result,writeback_data,csr_writeback_data,tmp_wbdata;
assign tmp_wbdata = (exe_to_mem_bus_r.sel_rf_wdata == `RFdata_ALU) & mem_valid ? exe_to_mem_bus_r.alu_result : load_result;
always_comb begin
    if(reset == `ON) begin 
        {load_result,writeback_data,csr_writeback_data} = `NULL;
    end else begin
        // load_result = data_sram_rdata_r;
        load_result = MASKED_data_sram_rdata;
        //正常模式：ALU/LOAD数据正常写入rf，此时忽略csr
        //异常模式：ALU数据写入csr，而读取的csr数据写入rf
        writeback_data = (exe_to_mem_bus_r.sel_exception == `EXC_ON) & mem_valid ? exe_to_mem_bus_r.rfc_wdata : tmp_wbdata;
        csr_writeback_data = tmp_wbdata;
    end
end


assign mem_to_id_bypass = '{
    exe_to_mem_bus_r.rf_wen & mem_valid,
    exe_to_mem_bus_r.rf_waddr,
    writeback_data
};


endmodule
